package ch.ethz.fcl.metrobuzz.data.loader.plan;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import ch.ethz.fcl.metrobuzz.data.MBData;
import ch.ethz.fcl.metrobuzz.data.scene.spacetime.Agent;
import ch.ethz.fcl.metrobuzz.data.scene.spacetime.Itinerary;
import ch.ethz.fcl.metrobuzz.tools.MBTools;

/**
 * divide agent data set into segments and load it one segment by one segment
 * 
 * @author Zeng Wei
 * @email zeng@arch.ethz.ch
 * 
 */
public class PlanFileLoader {
	private SAXParserFactory parserFactory = SAXParserFactory.newInstance();
	// General: Agent > Itinerary > Trips > Path
	// MatSim: Person > Plan > Routes > Nodes
	private String agentName = "person";
	private String itineraryName = "plan";
	private String tripName = "route";

	// size of current segment
	// private int agentLimit = 10000;

	private MBData data;
	private String agentFile;

	private final boolean DEBUG = true;

	public PlanFileLoader(MBData data, String path) {
		this.data = data;
		this.agentFile = path;
	}

	public void loadAgents() {
		try {
			SAXParser parser = parserFactory.newSAXParser();
			parser.parse(agentFile, new DefaultHandler() {
				@Override
				public InputSource resolveEntity(String publicId,
						String systemId) throws org.xml.sax.SAXException,
						java.io.IOException {
					System.out.println("Ignoring: " + publicId + ", "
							+ systemId);
					return new InputSource(new java.io.StringReader(""));
				}

				// Plan variables
				Agent agent = null;
				Itinerary itinerary = null;
				String type;
				float tdep = 0;
				float tarr = 0;
				boolean addRoute = false;
				boolean isPT = false;

				// Plan variables
				boolean isSelected = false;

				int tripIndex = 0;
				float end_time = 0;

				int count = 0;
				int tripsSize = 0;

				// int x = 0;

				@Override
				public void startElement(String uri, String localName,
						String name, Attributes attributes) throws SAXException {
					// If you find a <person>
					if (name.equals(agentName)) {
						count++;

						agent = new Agent(data.getScene().getAgentMap().size());
						data.getScene().addAgent(agent.getAgentId(), agent);

						// calculating interchange for every segment
						// if (data.getScene().getAgents().size() > agentLimit)
						// {
						// MBTools.debug(
						// "Agent name "
						// + attributes.getValue("id")
						// + " count "
						// + count
						// + " agent size "
						// + data.getScene().getAgents()
						// .size() + " trip size "
						// + tripsSize, true);
						// if (MBProperty.MRT)
						// interchange.getJunctionWriter()
						// .calJunctionDistributions(interchange);
						//
						// if (MBProperty.REGIONS)
						// interchange.getRegionWriter()
						// .calRegionDistributions(interchange);
						// data.getScene().clean();
						//
						// // x++;
						// }

						// if (x >= 1)
						// throw new SAXException("limit reached");
					} else if (name.equals(itineraryName)) {
						if (attributes.getValue("selected").equals("yes"))
							isSelected = true;
						else
							isSelected = false;
						if (isSelected) {
							itinerary = new Itinerary(agent);
							agent.setItinerary(itinerary);
						}
					} else if (name.equals("act")) {
						type = attributes.getValue("type");
						// don't add the act type since the trip is not
						// added
						// if there is no trip nodes
						if (isSelected) {
							if (!type.equals("pt interaction")) {
								MBTools.debug(attributes.getValue("end_time"),
										false);
								end_time = MBTools
										.convertTimeFromString(attributes
												.getValue("end_time"));
								// new trip start
								if (end_time != 0)
									tripIndex++;
							}
						}
					} else if (name.equals("leg")) {
						if (attributes.getValue("mode").equals("pt"))
							isPT = true;
						else if (attributes.getValue("mode").equals("car"))
							isPT = false;
						else
							isPT = false;

						if (isSelected) {
							itinerary.setPT(isPT);

							float travel_time = MBTools
									.convertTimeFromString(attributes
											.getValue("trav_time"));
							if (isPT) {
								tdep = end_time;
								tarr = tdep + travel_time;
								end_time += travel_time;
							} else {
								end_time += travel_time;
							}
						}
					} else if (name.equals(tripName)) {
						addRoute = true;
					}
				}

				@Override
				public void endElement(String uri, String localName, String name)
						throws SAXException {
					if (name.equals(tripName))
						addRoute = false;
					if (name.equals("population")) {
						if (DEBUG)
							System.out.println("Input  count " + count
									+ " total agent size "
									+ data.getScene().getAgentMap().size()
									+ " trip size " + tripsSize);
						// if (MBProperty.MRT)
						// interchange.getJunctionWriter()
						// .writeJunctionDistributions(interchange);
						// if (MBProperty.REGIONS)
						// interchange.getRegionWriter()
						// .writeRegionDistributions(interchange);

						// TransactionWriter.closeWriter();
					}
				}

				@Override
				public void characters(char[] ch, int start, int length)
						throws SAXException {
					if (isSelected && addRoute && isPT) {
						itinerary.addTrips(data, tripIndex, tdep, tarr, ch,
								start, length);
						tripsSize += itinerary.getTrips().size();
					}
				}
			});
		} catch (Exception e) {
			// if (MBProperty.MRT)
			// interchange.getJunctionWriter().writeJunctionDistributions(
			// interchange);
			// if (MBProperty.REGIONS)
			// interchange.getRegionWriter().writeRegionDistributions(
			// interchange);
			e.printStackTrace();
		}
	}
}